package dawnland03.model.action.parameter;

import dawnland03.model.item.Item;
import dawnland03.model.item.ItemType;

import java.util.*;

/**
 * User: Petru Obreja (obrejap@yahoo.com)
 * Date: May 25, 2010
 * Time: 7:50:00 PM
 */
public class OutputParameters {
    private final Map<ActionOutputParam, Object> actionOutputParams = new HashMap<ActionOutputParam, Object>();

    /*
    * DESTINATION : a list of matrixCellIds; for a move action, it will only one cell; for a task, it will be the path followed
    * DURATION : Long; for a group task, is the total duration of all subtasks
    * ITEM: Map<ItemType, Set<Item>>; for each ItemType, the Set of items collected
    * OWNER_SNAPSHOT: EntitySnapshot; the state of the owner from the moment when the action/the last subtask ended
    * STARTING_POSITION: Integer
    * COMPLETED: boolean
    */

    public OutputParameters() {
        initActionOutputParams();
    }

    private void initActionOutputParams() {
        for (ActionOutputParam actionOutputParam : ActionOutputParam.values()) {
            switch (actionOutputParam) {
                case DESTINATION:
                    //values will be added to this list
                    actionOutputParams.put(actionOutputParam, new LinkedList<Integer>());
                    break;
                case DURATION:
                    //values will be added to this initial value
                    actionOutputParams.put(actionOutputParam, (long) 0.0);
                    break;
                case ITEM:
                    Map<ItemType, Set<Item>> itemsMap = new HashMap<ItemType, Set<Item>>();
                    for (ItemType itemType : ItemType.values()) {
                        itemsMap.put(itemType, new HashSet<Item>());
                    }
                    actionOutputParams.put(actionOutputParam, itemsMap);
                    break;
                case COMPLETED:
                    actionOutputParams.put(actionOutputParam, true);
                    break;
                case OWNER_SNAPSHOT:
                case STARTING_POSITION:
                    //do nothing; values will be overwritten
                    break;
                default:
                    throw new IllegalStateException("unhandled " + actionOutputParam + " by " + OutputParameters.class.getName());
            }
        }
    }

    public void addOutputParamValues(OutputParameters outputParameters) {
        if (outputParameters != null) {
            for (Map.Entry<ActionOutputParam, Object> actionOutputParamValue : outputParameters.actionOutputParams.entrySet()) {
                Object value = actionOutputParamValue.getValue();
                ActionOutputParam actionOutputParam = actionOutputParamValue.getKey();
                addOutputParamValue(actionOutputParam, value);
            }
        }
    }

    public void addOutputParamValue(ActionOutputParam actionOutputParam, Object value) {
        Object currentStoredValue = actionOutputParams.get(actionOutputParam);
        if (value != null) {
            try {
                switch (actionOutputParam) {
                    case DESTINATION:
                        if (value instanceof Integer) {
                            ((List<Integer>) currentStoredValue).add((Integer) value);
                        } else {
                            ((List<Integer>) currentStoredValue).addAll((Collection<? extends Integer>) value);
                        }
                        break;
                    case DURATION:
                        actionOutputParams.put(actionOutputParam, (Long) currentStoredValue + (Long) value);
                        break;
                    case ITEM:
                        Map<ItemType, Set<Item>> itemsMap = (Map<ItemType, Set<Item>>) currentStoredValue;
                        if (value instanceof Collection) {
                            Collection<Item> items = (Collection<Item>) value;
                            if (items.size() > 0) {
                                for (Item item : items) {
                                    itemsMap.get(item.getItemType()).add(item);
                                }
                            }
                        } else {
                            Map<ItemType, Set<Item>> items = (Map<ItemType, Set<Item>>) value;
                            if (items.size() > 0) {
                                for (Map.Entry<ItemType, Set<Item>> itemEntry : items.entrySet()) {
                                    itemsMap.get(itemEntry.getKey()).addAll(itemEntry.getValue());
                                }
                            }
                        }
                        break;
                    case OWNER_SNAPSHOT:
                    case STARTING_POSITION:
                        actionOutputParams.put(actionOutputParam, value);
                        break;
                    case COMPLETED:
                        if (((Boolean) value) == false) {
                            actionOutputParams.put(actionOutputParam, false); //false overwrites
                        }
                        break;
                    default:
                        throw new IllegalStateException("unhandled " + actionOutputParam + " by " + OutputParameters.class.getName());
                }
            } catch (Exception e) {
                System.err.println("Exception in Task.addOutputParamValue(): " + e);
            }
        }
    }

    public Object getOutputParameter(ActionOutputParam actionOutputParam) {
        return actionOutputParams.get(actionOutputParam);
    }

}
